package httpserver

import (
	"encoding/json"
	"fmt"
	"net/http"

	"example.com/dcache/cache"
	"example.com/dcache/logger"
	"example.com/dcache/nodes"
	"github.com/gin-gonic/gin"
)

type PostData struct {
	GroupName string `json:"GroupName" form:"GroupName"`
	Key       string `json:"key" form:"key"`
	Value     []byte `json:"value" form:"value"`
	Info      string `json:"info" form:"info"`
}

// @Summary 建立组
// @Produce json
// @Param groupName path string true "组名称"
// @Success 200 "成功"
// @Failure 400 "请求错误"
// @Failure 500 "内部错误"
// @Router /1.0/api/Groups/{groupName} [post]
func setGroups(c *gin.Context) {
	groupName := c.Param("groupName")

	if err := cache.SetGroups(groupName, 0, nil); err != nil {
		c.JSON(http.StatusNotFound, gin.H{
			"err":    err.Error(),
			"node":   "",
			"status": http.StatusNotFound,
		})
		return
	}

	nodes := ""
	for _, node := range cache.GetAllNodes(groupName) {
		nodes = nodes + node + ", "
	}

	c.JSON(http.StatusOK, gin.H{
		"err":    nil,
		"node":   nodes,
		"status": http.StatusOK,
	})
}

// setGroupLocal sets up a new group with given group name
func setGroupLocal(c *gin.Context) {
	groupName := c.Param("groupName")

	if err := cache.SetGroupLocal(groupName, 0, nil); err != nil {
		c.JSON(http.StatusNotFound, gin.H{
			"err":    err.Error(),
			"node":   "",
			"status": http.StatusNotFound,
		})
		fmt.Println(err)
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"err":    nil,
		"node":   "",
		"status": http.StatusOK,
	})
}

// deleteGroupLocal delete a group with given group name
func deleteGroupLocal(c *gin.Context) {
	groupName := c.Param("groupName")

	cache.DeleteGroupLocal(groupName)

	c.JSON(http.StatusOK, gin.H{
		"err":    nil,
		"node":   "",
		"status": http.StatusOK,
	})
}

// @Summary 获取所有组
// @Produce  json
// @Success 200 "成功"
// @Failure 400 "请求错误"
// @Failure 500 "内部错误"
// @Router /1.0/api/Groups [get]
func getAllGroups(c *gin.Context) {
	c.String(http.StatusOK, cache.GetAllGroups())
}

// @Summary 删除组
// @Produce json
// @Param groupName path string true "组名称"
// @Success 200 "成功"
// @Failure 400 "请求错误"
// @Failure 500 "内部错误"
// @Router /1.0/api/Groups/{groupName} [delete]
func deleteGroup(c *gin.Context) {
	groupName := c.Param("groupName")
	if err := cache.DeleteGroups(groupName); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"err": err.Error(),
		})

		return
	}

	/*
		nodes := ""
		for _, node := range cache.GetAllNodes(groupName) {
			nodes = nodes + node + ", "
		}*/

	c.JSON(http.StatusOK, gin.H{})
}

// @Summary 添加键值对
// @Produce json
// @Param GroupName body string true "组"
// @Param key body string true "键"
// @Param value body string true "值"
// @Param info body string false "帮助信息"
// @Success 200 "成功"
// @Failure 400 "请求错误"
// @Failure 500 "内部错误"
// @Router /1.0/api/keys [post]
func setOnTargetNode(c *gin.Context) {
	conn := c.GetHeader("Content-Type")
	fmt.Println("Connection", conn)
	keys := c.Keys
	fmt.Println("keys", keys)
	Accepted := c.Accepted
	fmt.Println("Accepted", Accepted)
	Proto := c.Request.Proto
	fmt.Println("Proto", Proto)
	Request := c.Request
	fmt.Println("Request", Request)

	var p PostData

	if err := c.ShouldBindJSON(&p); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{
			"node": "",
			"err":  err.Error(),
		})

		return
	}

	var node nodes.NodeHandler
	var err error
	if node, err = cache.SetOnTargetNode(p.GroupName, p.Key, p.Value); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"node":   "",
			"err":    err.Error(),
			"status": http.StatusInternalServerError,
		})

		return
	}

	if p.Info == "-info" {
		c.JSON(http.StatusOK, gin.H{
			"info":   cache.GetSelfAddress(p.GroupName),
			"status": http.StatusOK,
		})

		return
	}

	c.JSON(http.StatusOK, gin.H{
		"err":    nil,
		"node":   node.GetBaseAddr(),
		"status": http.StatusOK,
	})
}

// @Summary 获取值
// @Produce json
// @Param GroupName body string true "组"
// @Param key body string true "键"
// @Success 200 "成功"
// @Failure 400 "请求错误"
// @Failure 500 "内部错误"
// @Router /1.0/api/keys/?GroupName=x&key=y [get]
func getOnTargetNode(c *gin.Context) {
	var (
		p     PostData
		value []byte
		err   error
		node  nodes.NodeHandler
	)

	if err := c.ShouldBind(&p); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"node":   "",
			"err":    err.Error(),
			"status": http.StatusInternalServerError,
		})

		return
	}

	if node, value, err = cache.GetOnTargetNode(p.GroupName, p.Key); err != nil {
		c.JSON(http.StatusNotFound, gin.H{
			"node":   "",
			"err":    err.Error(),
			"status": http.StatusNotFound,
		})
		return
	}

	c.JSON(http.StatusOK, gin.H{
		"node":   node.GetBaseAddr(),
		"value":  string(value),
		"status": http.StatusOK,
	})
}

// @Summary 删除键值对
// @Produce json
// @Param GroupName body string true "组"
// @Param key body string true "键"
// @Success 200 "成功"
// @Failure 400 "请求错误"
// @Failure 500 "内部错误"
// @Router /1.0/api/keys [delete]
func deleteOnTargetNode(c *gin.Context) {
	var (
		p    PostData
		err  error
		node nodes.NodeHandler
	)

	if err = c.ShouldBind(&p); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"node":   "",
			"err":    err.Error(),
			"status": http.StatusInternalServerError,
		})

		return
	}

	if node, err = cache.DeleteOnTargetNode(p.GroupName, p.Key); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"node":   "",
			"err":    err.Error(),
			"status": http.StatusInternalServerError,
		})

		return
	}

	c.JSON(http.StatusOK, gin.H{
		"node":   node.GetBaseAddr(),
		"err":    nil,
		"status": http.StatusOK,
	})
}

// setLocal sets a given key-value in a given group
func setLocal(c *gin.Context) {
	groupName := c.Param("groupName")
	key := c.Param("key")
	value := c.Param("value")
	node := cache.GetSelfAddress(groupName)

	if err := cache.Set(groupName, key, []byte(value)); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"node":   node,
			"err":    err.Error(),
			"status": http.StatusInternalServerError,
		})

		return
	}

	c.JSON(http.StatusOK, gin.H{
		"node":   node,
		"err":    nil,
		"status": http.StatusOK,
	})
}

// getLocal returns specified group's key's value, the returned value's Content-Type is json
func getLocal(c *gin.Context) {
	var (
		value []byte
		err   error
	)

	groupName := c.Param("groupName")
	key := c.Param("key")
	node := cache.GetSelfAddress(groupName)

	if value, err = cache.Get(groupName, key); err != nil {
		c.JSON(http.StatusNotFound, gin.H{
			"node":   node,
			"err":    err.Error(),
			"status": http.StatusNotFound,
		})

		return
	}

	c.JSON(http.StatusOK, gin.H{
		"node":   node,
		"value":  string(value),
		"status": http.StatusOK,
	})
}

// deleteLocal deletes a given key-value in a given group
func deleteLocal(c *gin.Context) {
	groupName := c.Param("groupName")
	key := c.Param("key")
	node := cache.GetSelfAddress(groupName)

	if err := cache.Delete(groupName, key); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"node":   node,
			"err":    err.Error(),
			"status": http.StatusInternalServerError,
		})

		return
	}

	c.JSON(http.StatusOK, gin.H{
		"node":   node,
		"err":    nil,
		"status": http.StatusOK,
	})
}

func updateGlobalNodesList(c *gin.Context) {
	var nodes map[string]string

	if err := c.ShouldBindJSON(&nodes); err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"err":    err.Error(),
			"status": http.StatusInternalServerError,
		})

		return
	}

	cache.UpdateNodesList(nodes)
}

func getAllElements(c *gin.Context) {
	groupName := c.Param("groupName")

	mapResult := cache.GetAllElements(groupName)
	jsonResult, err := json.Marshal(mapResult)

	if err != nil {
		c.String(404, err.Error())
	}

	logger.Debug("All elements in group %s: %s", groupName, string(jsonResult))

	c.String(200, string(jsonResult))
}
